using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Design;
using System.Runtime.InteropServices;
using System.Web.UI;
using PickGold.Charting;
using PickGold.Charting.ChartTypes;
using PickGold.Charting.Utilities;
using PickGold.Charting.Design;

namespace PickGold.Charting.Data
{
	internal class DataManager : ChartElement, IServiceProvider
	{
		private ChartColorPalette _colorPalette = ChartColorPalette.BrightPastel;
		private Color[] _paletteCustomColors = new Color[0];
		private SeriesCollection _series;
		internal IServiceContainer serviceContainer;

		public DataManager(IServiceContainer container)
		{
			if (container == null)
			{
				throw new ArgumentNullException(SR.ExceptionInvalidServiceContainer);
			}
			this.serviceContainer = container;
			base.Common = new CommonElements(container);
			this._series = new SeriesCollection(this);
		}

		internal void ApplyPaletteColors()
		{
			var brightPastel = this.Palette;
			if ((brightPastel == ChartColorPalette.None) && (this.PaletteCustomColors.Length == 0))
			{
				brightPastel = ChartColorPalette.BrightPastel;
			}
			var num = 0;
			var colorArray = (brightPastel == ChartColorPalette.None) ? this.PaletteCustomColors : ChartPaletteColors.GetPaletteColors(brightPastel);
			foreach (var series in this._series)
			{
				var flag = false;
				if (base.Chart != null)
				{
					flag = base.Chart.ChartAreas.IsNameReferenceValid(series.ChartArea);
				}
				if (flag && ((series.Color == Color.Empty) || series.tempColorIsSet))
				{
					series.color = colorArray[num++];
					series.tempColorIsSet = true;
					if (num >= colorArray.Length)
					{
						num = 0;
					}
				}
			}
		}

		private void ChartPicture_AfterPaint(object sender, ChartPaintEventArgs e)
		{
			var service = (Chart)this.serviceContainer.GetService(typeof(Chart));
			if (service != null)
			{
				for (var i = 0; i < this.Series.Count; i++)
				{
					var series = this.Series[i];
					if (series.UnPrepareData(service.Site))
					{
						i--;
					}
				}
			}
		}

		private void ChartPicture_BeforePaint(object sender, ChartPaintEventArgs e)
		{
			var num = 1;
			for (var i = 0; i < this.Series.Count; i++)
			{
				var series = this.Series[i];
				series.xValuesZerosChecked = false;
				series.xValuesZeros = false;
				var chartType = e.CommonElements.ChartTypeRegistry.GetChartType(series.ChartTypeName);
				bool applyPaletteColorsToPoints = chartType.ApplyPaletteColorsToPoints;
				if (series.Palette != ChartColorPalette.None)
				{
					applyPaletteColorsToPoints = true;
				}
				this.PrepareData(applyPaletteColorsToPoints, new string[] { series.Name });
				if (series.tempMarkerStyleIsSet)
				{
					series.MarkerStyle = MarkerStyle.None;
					series.tempMarkerStyleIsSet = false;
				}
				if ((chartType.GetLegendImageStyle(series) == LegendImageStyle.Marker) && (series.MarkerStyle == MarkerStyle.None))
				{
					series.MarkerStyle = (MarkerStyle)num++;
					series.tempMarkerStyleIsSet = true;
					if (num > 9)
					{
						num = 1;
					}
				}
			}
		}

		protected override void Dispose(bool disposing)
		{
			if (disposing && (this._series != null))
			{
				this._series.Dispose();
				this._series = null;
			}
		}

		internal double GetMaxHundredPercentStackedYValue(bool supportNegative, params string[] series)
		{
			var num = 0.0D;
			var seriesArray = new Series[series.Length];
			int num2 = 0;
			foreach (var str in series)
				seriesArray[num2++] = this._series[str];
			try
			{
				for (var i = 0; i < this._series[series[0]].Points.Count; i++)
				{
					var num4 = 0.0D;
					var num5 = 0.0D;
					foreach (var series2 in seriesArray)
					{
						if (supportNegative)
							num4 += Math.Abs(series2.Points[i].YValues[0]);
						else
							num4 += series2.Points[i].YValues[0];
						if ((series2.Points[i].YValues[0] > 0.0) || !supportNegative)
							num5 += series2.Points[i].YValues[0];
					}
					num4 = Math.Abs(num4);
					if (num4 != 0.0)
						num = Math.Max(num, (num5 / num4) * 100.0);
				}
			}
			catch (Exception)
			{
				throw new InvalidOperationException(SR.ExceptionDataManager100StackedSeriesPointsNumeberMismatch);
			}
			return num;
		}

		internal double GetMaxStackedXValue(params string[] series)
		{
			double num = 0.0;
			double numberOfPoints = this.GetNumberOfPoints(series);
			for (int i = 0; i < numberOfPoints; i++)
			{
				double num4 = 0.0;
				foreach (string str in series)
				{
					if ((this._series[str].Points.Count > i) && (this._series[str].Points[i].XValue > 0.0))
					{
						num4 += this._series[str].Points[i].XValue;
					}
				}
				num = Math.Max(num, num4);
			}
			return num;
		}

		internal double GetMaxStackedYValue(int valueIndex, params string[] series)
		{
			double num = 0.0;
			double numberOfPoints = this.GetNumberOfPoints(series);
			for (int i = 0; i < numberOfPoints; i++)
			{
				double num4 = 0.0;
				double num5 = 0.0;
				foreach (string str in series)
				{
					if (this._series[str].Points.Count > i)
					{
						IChartType chartType = ((ChartTypeRegistry)this.serviceContainer.GetService(typeof(ChartTypeRegistry))).GetChartType(this._series[str].ChartTypeName);
						if (chartType.StackSign)
						{
							if (chartType.Stacked)
							{
								if (this._series[str].Points[i].YValues[valueIndex] > 0.0)
								{
									num4 += this._series[str].Points[i].YValues[valueIndex];
								}
							}
							else
							{
								num5 = Math.Max(num5, this._series[str].Points[i].YValues[valueIndex]);
							}
						}
					}
				}
				num4 = Math.Max(num4, num5);
				num = Math.Max(num, num4);
			}
			return num;
		}

		internal double GetMaxUnsignedStackedYValue(int valueIndex, params string[] series)
		{
			double num = 0.0;
			double minValue = double.MinValue;
			double numberOfPoints = this.GetNumberOfPoints(series);
			for (int i = 0; i < numberOfPoints; i++)
			{
				double num5 = 0.0;
				double num6 = 0.0;
				foreach (string str in series)
				{
					if (this._series[str].Points.Count > i)
					{
						IChartType chartType = ((ChartTypeRegistry)this.serviceContainer.GetService(typeof(ChartTypeRegistry))).GetChartType(this._series[str].ChartTypeName);
						if (!chartType.StackSign && !double.IsNaN(this._series[str].Points[i].YValues[valueIndex]))
						{
							if (chartType.Stacked)
							{
								minValue = double.MinValue;
								num5 += this._series[str].Points[i].YValues[valueIndex];
								if (num5 > minValue)
								{
									minValue = num5;
								}
							}
							else
							{
								num6 = Math.Max(num6, this._series[str].Points[i].YValues[valueIndex]);
							}
						}
					}
				}
				minValue = Math.Max(minValue, num6);
				num = Math.Max(num, minValue);
			}
			return num;
		}

		internal double GetMaxXValue(params string[] series)
		{
			double minValue = double.MinValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					minValue = Math.Max(minValue, point.XValue);
				}
			}
			return minValue;
		}

		internal double GetMaxXWithRadiusValue(ChartArea area, params string[] series)
		{
			double minValue = double.MinValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point) && !double.IsNaN(point.XValue))
					{
						if (point.YValues.Length > 1)
						{
							minValue = Math.Max(minValue, point.XValue + BubbleChart.AxisScaleBubbleSize(area.Common, area, point.XValue, false));
						}
						else
						{
							minValue = Math.Max(minValue, point.XValue);
						}
					}
				}
			}
			return minValue;
		}

		internal double GetMaxYValue(params string[] series)
		{
			double minValue = double.MinValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point))
					{
						foreach (double num2 in point.YValues)
						{
							if (!double.IsNaN(num2))
							{
								minValue = Math.Max(minValue, num2);
							}
						}
					}
				}
			}
			return minValue;
		}

		internal double GetMaxYValue(int valueIndex, params string[] series)
		{
			double minValue = double.MinValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point) && !double.IsNaN(point.YValues[valueIndex]))
					{
						minValue = Math.Max(minValue, point.YValues[valueIndex]);
					}
				}
			}
			return minValue;
		}

		internal double GetMaxYWithRadiusValue(ChartArea area, params string[] series)
		{
			double minValue = double.MinValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point) && !double.IsNaN(point.YValues[0]))
					{
						if (point.YValues.Length > 1)
						{
							minValue = Math.Max(minValue, point.YValues[0] + BubbleChart.AxisScaleBubbleSize(area.Common, area, point.YValues[1], true));
						}
						else
						{
							minValue = Math.Max(minValue, point.YValues[0]);
						}
					}
				}
			}
			return minValue;
		}

		internal double GetMinHundredPercentStackedYValue(bool supportNegative, params string[] series)
		{
			var num = 0.0D;
			var seriesArray = new Series[series.Length];
			var num2 = 0;
			foreach (var str in series)
				seriesArray[num2++] = this._series[str];
			try
			{
				for (var i = 0; i < this._series[series[0]].Points.Count; i++)
				{
					var num4 = 0.0D;
					var num5 = 0.0D;
					foreach (var series2 in seriesArray)
					{
						if (supportNegative)
						{
							num4 += Math.Abs(series2.Points[i].YValues[0]);
						}
						else
						{
							num4 += series2.Points[i].YValues[0];
						}
						if ((series2.Points[i].YValues[0] < 0.0) || !supportNegative)
						{
							num5 += series2.Points[i].YValues[0];
						}
					}
					num4 = Math.Abs(num4);
					if (num4 != 0.0)
					{
						num = Math.Min(num, (num5 / num4) * 100.0);
					}
				}
			}
			catch (Exception)
			{
				throw new InvalidOperationException(SR.ExceptionDataManager100StackedSeriesPointsNumeberMismatch);
			}
			return num;
		}

		internal void GetMinMaxXValue(out double min, out double max, params string[] series)
		{
			max = double.MinValue;
			min = double.MaxValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					max = Math.Max(max, point.XValue);
					min = Math.Min(min, point.XValue);
				}
			}
		}

		internal void GetMinMaxYValue(out double min, out double max, params string[] series)
		{
			max = double.MinValue;
			min = double.MaxValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point))
					{
						foreach (double num in point.YValues)
						{
							if (!double.IsNaN(num))
							{
								max = Math.Max(max, num);
								min = Math.Min(min, num);
							}
						}
					}
				}
			}
		}

		internal void GetMinMaxYValue(List<Series> seriesList, out double min, out double max)
		{
			max = double.MinValue;
			min = double.MaxValue;
			foreach (var series in seriesList)
			{
				foreach (var point in series.Points)
				{
					if (!this.IsPointSkipped(point))
					{
						foreach (var num in point.YValues)
						{
							if (!double.IsNaN(num))
							{
								max = Math.Max(max, num);
								min = Math.Min(min, num);
							}
						}
					}
				}
			}
		}

		internal void GetMinMaxYValue(int valueIndex, out double min, out double max, params string[] series)
		{
			max = double.MinValue;
			min = double.MaxValue;
			foreach (var str in series)
			{
				foreach (var point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point))
					{
						var d = point.YValues[valueIndex];
						if (!double.IsNaN(d))
						{
							max = Math.Max(max, d);
							min = Math.Min(min, d);
						}
					}
				}
			}
		}

		internal double GetMinStackedXValue(params string[] series)
		{
			double num = 0.0;
			double numberOfPoints = this.GetNumberOfPoints(series);
			for (int i = 0; i < numberOfPoints; i++)
			{
				double num4 = 0.0;
				foreach (string str in series)
				{
					if (this._series[str].Points[i].XValue < 0.0)
					{
						num4 += this._series[str].Points[i].XValue;
					}
				}
				num = Math.Min(num, num4);
			}
			return num;
		}

		internal double GetMinStackedYValue(int valueIndex, params string[] series)
		{
			double maxValue = double.MaxValue;
			double numberOfPoints = this.GetNumberOfPoints(series);
			for (int i = 0; i < numberOfPoints; i++)
			{
				double num4 = 0.0;
				double num5 = 0.0;
				foreach (string str in series)
				{
					if (this._series[str].Points.Count > i)
					{
						IChartType chartType = ((ChartTypeRegistry)this.serviceContainer.GetService(typeof(ChartTypeRegistry))).GetChartType(this._series[str].ChartTypeName);
						if (chartType.StackSign && !double.IsNaN(this._series[str].Points[i].YValues[valueIndex]))
						{
							if (chartType.Stacked)
							{
								if (this._series[str].Points[i].YValues[valueIndex] < 0.0)
								{
									num4 += this._series[str].Points[i].YValues[valueIndex];
								}
							}
							else
							{
								num5 = Math.Min(num5, this._series[str].Points[i].YValues[valueIndex]);
							}
						}
					}
				}
				num4 = Math.Min(num4, num5);
				if (num4 == 0.0)
				{
					num4 = this._series[series[0]].Points[this._series[series[0]].Points.Count - 1].YValues[valueIndex];
				}
				maxValue = Math.Min(maxValue, num4);
			}
			return maxValue;
		}

		internal double GetMinUnsignedStackedYValue(int valueIndex, params string[] series)
		{
			double maxValue = double.MaxValue;
			double num2 = double.MaxValue;
			double numberOfPoints = this.GetNumberOfPoints(series);
			for (int i = 0; i < numberOfPoints; i++)
			{
				double num5 = 0.0;
				double num6 = 0.0;
				num2 = double.MaxValue;
				foreach (string str in series)
				{
					if (this._series[str].Points.Count > i)
					{
						IChartType chartType = ((ChartTypeRegistry)this.serviceContainer.GetService(typeof(ChartTypeRegistry))).GetChartType(this._series[str].ChartTypeName);
						if (!chartType.StackSign && !double.IsNaN(this._series[str].Points[i].YValues[valueIndex]))
						{
							if (chartType.Stacked)
							{
								if (this._series[str].Points[i].YValues[valueIndex] < 0.0)
								{
									num5 += this._series[str].Points[i].YValues[valueIndex];
									if (num5 < num2)
									{
										num2 = num5;
									}
								}
							}
							else
							{
								num6 = Math.Min(num6, this._series[str].Points[i].YValues[valueIndex]);
							}
						}
					}
				}
				num2 = Math.Min(num6, num2);
				maxValue = Math.Min(maxValue, num2);
			}
			return maxValue;
		}

		internal double GetMinXValue(params string[] series)
		{
			double maxValue = double.MaxValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					maxValue = Math.Min(maxValue, point.XValue);
				}
			}
			return maxValue;
		}

		internal double GetMinXWithRadiusValue(ChartArea area, params string[] series)
		{
			double maxValue = double.MaxValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point) && !double.IsNaN(point.XValue))
					{
						if (point.YValues.Length > 1)
						{
							maxValue = Math.Min(maxValue, point.XValue - BubbleChart.AxisScaleBubbleSize(area.Common, area, point.YValues[1], false));
						}
						else
						{
							maxValue = Math.Min(maxValue, point.XValue);
						}
					}
				}
			}
			return maxValue;
		}

		internal double GetMinYValue(params string[] series)
		{
			double maxValue = double.MaxValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point))
					{
						foreach (double num2 in point.YValues)
						{
							if (!double.IsNaN(num2))
							{
								maxValue = Math.Min(maxValue, num2);
							}
						}
					}
				}
			}
			return maxValue;
		}

		internal double GetMinYValue(int valueIndex, params string[] series)
		{
			double maxValue = double.MaxValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point) && !double.IsNaN(point.YValues[valueIndex]))
					{
						maxValue = Math.Min(maxValue, point.YValues[valueIndex]);
					}
				}
			}
			return maxValue;
		}

		internal double GetMinYWithRadiusValue(ChartArea area, params string[] series)
		{
			double maxValue = double.MaxValue;
			foreach (string str in series)
			{
				foreach (DataPoint point in this._series[str].Points)
				{
					if (!this.IsPointSkipped(point) && !double.IsNaN(point.YValues[0]))
					{
						if (point.YValues.Length > 1)
						{
							maxValue = Math.Min(maxValue, point.YValues[0] - BubbleChart.AxisScaleBubbleSize(area.Common, area, point.YValues[1], true));
						}
						else
						{
							maxValue = Math.Min(maxValue, point.YValues[0]);
						}
					}
				}
			}
			return maxValue;
		}

		internal int GetNumberOfPoints(params string[] series)
		{
			int num = 0;
			foreach (string str in series)
			{
				num = Math.Max(num, this._series[str].Points.Count);
			}
			return num;
		}

		internal void Initialize()
		{
			ChartImage service = (ChartImage)this.serviceContainer.GetService(typeof(ChartImage));
			service.BeforePaint += new EventHandler<ChartPaintEventArgs>(this.ChartPicture_BeforePaint);
			service.AfterPaint += new EventHandler<ChartPaintEventArgs>(this.ChartPicture_AfterPaint);
		}

		internal override void Invalidate()
		{
			base.Invalidate();
		}

		private bool IsPointSkipped(DataPoint point)
		{
			return point.IsEmpty;
		}

		internal void PrepareData(bool pointsApplyPaletteColors, params string[] series)
		{
			this.ApplyPaletteColors();
			Chart service = (Chart)this.serviceContainer.GetService(typeof(Chart));
			if (service != null)
			{
				foreach (string str in series)
				{
					this.Series[str].PrepareData(service.Site, pointsApplyPaletteColors);
				}
			}
		}

		[EditorBrowsable(EditorBrowsableState.Never)]
		object IServiceProvider.GetService(Type serviceType)
		{
			if (serviceType != typeof(DataManager))
			{
				throw new ArgumentException(SR.ExceptionDataManagerUnsupportedType(serviceType.ToString()));
			}
			return this;
		}

		[PersistenceMode(PersistenceMode.InnerProperty), Editor(typeof(ColorPaletteEditor), typeof(UITypeEditor)), DefaultValue(12), SRCategory("CategoryAttributeAppearance"), Bindable(true), SRDescription("DescriptionAttributePalette")]
		public ChartColorPalette Palette
		{
			get
			{
				return this._colorPalette;
			}
			set
			{
				this._colorPalette = value;
			}
		}

		[SRDescription("DescriptionAttributeDataManager_PaletteCustomColors"), SRCategory("CategoryAttributeAppearance"), TypeConverter(typeof(ColorArrayConverter)), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), SerializationVisibility(SerializationVisibility.Attribute)]
		public Color[] PaletteCustomColors
		{
			get
			{
				return this._paletteCustomColors;
			}
			set
			{
				this._paletteCustomColors = value;
			}
		}

		[Editor(typeof(SeriesCollectionEditor), typeof(UITypeEditor)), Bindable(true), SRCategory("CategoryAttributeData"), PersistenceMode(PersistenceMode.InnerProperty)]
		public SeriesCollection Series
		{
			get
			{
				return this._series;
			}
		}
	}
}

